#pragma once

#include <iostream>
#include <cstdio>
#include <cstring>
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>

//using namespace std;

static const std::string defaultip = "0.0.0.0";
static const int gnum = 1024;
enum{SOCKERRO = 2,BINDERRO};

class udpServer{
public:
    udpServer(const uint16_t port) :_port(port),_ip(defaultip)
    {};

    void initServer(){
        _sockfd = socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd == -1){
            std::cerr<<"socket fild:"<<errno<<strerror(errno)<<std::endl;
            exit(SOCKERRO);
        }
        struct sockaddr_in local;
        bzero(&local,sizeof local);
        local.sin_family = AF_INET;       //指定协议
        local.sin_port = htons(_port);    //本机数据网络数据转换需要考虑大小端！！！
        local.sin_addr.s_addr = htonl(INADDR_ANY); //指定ip，可以是任意ip
        int r = bind(_sockfd,(sockaddr*)&local,sizeof local);
        if(r == -1){
            std::cerr<<"bind fild:"<<errno<<strerror(errno)<<std::endl;
            exit(BINDERRO);
        }
    }

    void start(){
        while(true){
            char buffer[gnum];
            sockaddr_in peer;
            socklen_t len = sizeof peer;
            ssize_t r = recvfrom(_sockfd,buffer,sizeof(buffer) -1,0,(sockaddr*)&peer,&len);  //空出一位
            if(r > 0){
                buffer[r] = 0;
                std::string ip = inet_ntoa(peer.sin_addr);   //inet_ntoa 从网络转为a字符串  inet_addr 从字符串转为uint16_t
                uint16_t port = ntohs(peer.sin_port);
                std::cout<<ip<<"["<<port<<"]"<<":"<<buffer<<std::endl;
            }
        }
    }

    ~udpServer(){}

private:
    std::string _ip;
    uint16_t _port;
    int _sockfd;
};